package threading;

/**
 * Created with IntelliJ IDEA.
 * Description:阻塞队列简单实现
 * User: xwl
 * Date: 2023-08-10
 * Time: 17:52
 */
// 1.基于数组来实现队列 2.加上线程安全 3.加上阻塞功能
class MyBlockingQueue {
    private int[] items = new int[1000];
    // 约定 [head,tail) 为队列的有效元素
    volatile private int head = 0;
    volatile private int tail = 0;
    volatile private int size = 0;
    // 入队列
    synchronized public void put(int elem) throws InterruptedException {
        while (size == items.length) {
//            // 队列满了,插入失败
//            return;
            // 队列满,进行阻塞
            this.wait();
        }
        // 把新元素放到 tail 所在的位置
        items[tail] = elem;
        tail++;
        // 万一 tail 达到末尾,就需要开始循环
        if (tail == items.length) {
            tail = 0;
        }
        size++;
        this.notify();
    }
    // 出队列
    synchronized public Integer take() throws InterruptedException {
        while (size == 0) {
//            return null;
            // 队列空,进行阻塞
            this.wait();
        }
        int value = items[head];
        head++;
        if (head == items.length) {
            head = 0;
        }
        size--;
        // 出队列进行唤醒
        this.notify();
        return value;
    }

}

public class ThreadDemo18 {
    public static void main(String[] args) {
        MyBlockingQueue queue = new MyBlockingQueue();

        // 消费者
        Thread t1 = new Thread( () -> {
            while (true) {
                try {
                    int value = queue.take();
                    System.out.println("消费: " + value);
                    Thread.sleep(1000);

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        // 生产者
        Thread t2 = new Thread( () -> {
            int value = 0;
            while (true) {
                try {
                    System.out.println("生产: " + value);
                    queue.put(value);
                    value++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t1.start();
        t2.start();
    }
}
